package cn.iocoder.yudao.module.product.spu.controller.admin;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.validation.groups.UpdateGroup;
import cn.iocoder.yudao.module.api.infrastructure.config.ConfigApiV2;
import cn.iocoder.yudao.module.api.infrastructure.config.dto.MemberConfigRespDTO;
import cn.iocoder.yudao.module.api.product.spu.enums.ProductSpuRecommendEnum;
import cn.iocoder.yudao.module.api.product.spu.enums.ProductSpuStatusEnum;
import cn.iocoder.yudao.module.api.shop.info.ShopInfoApi;
import cn.iocoder.yudao.module.api.shop.info.dto.ShopInfoDTO;
import cn.iocoder.yudao.module.product.brand.dal.dataobject.ProductBrandDO;
import cn.iocoder.yudao.module.product.brand.service.ProductBrandService;
import cn.iocoder.yudao.module.product.sku.dal.dataobject.ProductSkuDO;
import cn.iocoder.yudao.module.product.sku.service.ProductSkuService;
import cn.iocoder.yudao.module.product.sku.vo.ProductSkuRespVO;
import cn.iocoder.yudao.module.product.spu.convert.ProductSpuConvert;
import cn.iocoder.yudao.module.product.spu.dal.dataobject.ProductSpuDO;
import cn.iocoder.yudao.module.product.spu.service.ProductSpuService;
import cn.iocoder.yudao.module.product.spu.vo.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.FORBIDDEN;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserLastShopId;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.isSuperAdmin;
import static cn.iocoder.yudao.module.api.infrastructure.ConfigConstants.CONFIG_MEMBER;

@Tag(name = "管理后台 - 产品 SPU")
@RestController
@RequestMapping("/product/spu")
@Validated
public class ProductSpuController {

    @Resource
    private ProductSpuService productSpuService;
    @Resource
    private ProductSkuService productSkuService;
    @Resource
    private ProductBrandService productBrandService;

    @Resource
    private ShopInfoApi shopInfoApi;
    @Resource
    private ConfigApiV2 configApiV2;

    @PostMapping("/create")
    @Operation(summary = "创建产品 SPU")
    @PreAuthorize("@ss.hasRole('shop_admin')")
    public CommonResult<Long> createProductSpu(@Valid @RequestBody ProductSpuSaveReqVO reqVO) {
        return success(productSpuService.createSpu(reqVO));
    }

    @PutMapping("/update")
    @Operation(summary = "更新产品 SPU")
    @PreAuthorize("@ss.hasPermission('product:spu:update')")
    public CommonResult<Boolean> updateSpu(@Validated(value = UpdateGroup.class) @RequestBody ProductSpuSaveReqVO reqVO) {
        productSpuService.updateSpu(reqVO);
        return success(true);
    }

    @PutMapping("/update-status")
    @Operation(summary = "更新产品 SPU Status")
    @PreAuthorize("@ss.hasPermission('product:spu:update')")
    public CommonResult<Boolean> updateStatus(@Valid @RequestBody ProductSpuUpdateStatusReqVO updateReqVO) {
        productSpuService.updateSpuStatus(updateReqVO);
        return success(true);
    }

    @PutMapping("/update-recommend")
    @Operation(summary = "更新产品 SPU 推荐类型")
    @PreAuthorize("@ss.hasPermission('product:spu:update')")
    public CommonResult<Boolean> updateRecommend(@Valid @RequestBody ProductSpuUpdateRecommendReqVO updateReqVO) {
        if (ProductSpuRecommendEnum.ADVERT.getValue().equals(updateReqVO.getRecommend())) {
            return error(FORBIDDEN.getCode(), "没有权限设置为" + ProductSpuRecommendEnum.ADVERT.getName());
        }
        productSpuService.updateSpuRecommend(updateReqVO);
        return success(true);
    }

    @PutMapping("/update-sticky")
    @Operation(summary = "更新产品 SPU 置顶")
    @PreAuthorize("@ss.hasAnyRoles('super_admin', 'platform_admin', 'tenant_admin')")
    public CommonResult<Boolean> updateSticky(@Valid @RequestBody ProductSpuUpdateStickyReqVO updateReqVO) {
        productSpuService.updateSpuSticky(updateReqVO);
        return success(true);
    }

    @PutMapping("/update-recommend-sort")
    @Operation(summary = "更新产品 SPU 推荐类型及排序")
    @PreAuthorize("@ss.hasAnyRoles('super_admin', 'platform_admin', 'tenant_admin')")
    public CommonResult<Boolean> updateRecommendSort(@Valid @RequestBody ProductSpuUpdateRecommendSortReqVO updateReqVO) {
        productSpuService.updateRecommendSort(updateReqVO);
        return success(true);
    }

    @DeleteMapping("/delete")
    @Operation(summary = "删除产品 SPU")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    @PreAuthorize("@ss.hasPermission('product:spu:delete')")
    public CommonResult<Boolean> deleteSpu(@RequestParam("id") Long id) {
        productSpuService.deleteSpu(id);
        return success(true);
    }

    @GetMapping("/get-detail")
    @Operation(summary = "获得产品 SPU 明细")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    @PreAuthorize("@ss.hasPermission('product:spu:query')")
    public CommonResult<ProductSpuRespVO> getSpuDetail(@RequestParam("id") Long id) {
        // 获得产品 SPU
        ProductSpuDO spu = productSpuService.getSpu(id);
        if (spu == null) {
            ProductSpuRespVO respVO = new ProductSpuRespVO();
            respVO.setId(0L);
            return success(respVO);
        }
        // 查询产品 SKU
        List<ProductSkuDO> skus = productSkuService.getSkuListBySpuId(spu.getId());
        ProductSpuRespVO data = ProductSpuConvert.INSTANCE.convert(spu, skus);
        MemberConfigRespDTO config = configApiV2.getConfig(CONFIG_MEMBER, MemberConfigRespDTO.class);
        int pointDeductUnitPrice = 0;
        if (!config.isPointDeductDisable()) {
            pointDeductUnitPrice = config.getPointTradeDeductUnitPrice();
        }
        int cryptocurrencyDeductUnitPrice = config.getCryptocurrencyTradeDeductUnitPrice();
        toVo(data, pointDeductUnitPrice, cryptocurrencyDeductUnitPrice);
        data.setShop(shopInfoApi.getShopInfo(spu.getShopId()));
        return success(data);
    }

    @GetMapping("/list-all-simple")
    @Operation(summary = "获得产品 SPU 精简列表")
    @PreAuthorize("@ss.hasPermission('product:spu:query')")
    public CommonResult<List<ProductSpuSimpleRespVO>> getSpuSimpleList() {
        List<ProductSpuDO> list = productSpuService.getSpuListByStatus(ProductSpuStatusEnum.ENABLE.getStatus());
        List<ProductSpuSimpleRespVO> data = BeanUtils.toBean(list, ProductSpuSimpleRespVO.class);
        if (CollUtil.isEmpty(list)) {
            return success(Collections.emptyList());
        }
        return success(data);
    }

    @GetMapping("/list")
    @Operation(summary = "获得产品 SPU 列表")
    @Parameter(name = "spuIds", description = "spu 编号列表", required = true, example = "1,2,3")
    @PreAuthorize("@ss.hasPermission('product:spu:query')")
    public CommonResult<List<ProductSpuRespVO>> getSpuList(@RequestParam("spuIds") Collection<Long> spuIds) {
        List<ProductSpuRespVO> list = ProductSpuConvert.INSTANCE.convertForSpuDetailRespListVO(
                productSpuService.getSpuList(spuIds), productSkuService.getSkuListBySpuIds(spuIds));
        toVoList(list);
        return success(list);
    }

    @GetMapping("/page")
    @Operation(summary = "获得产品 SPU 分页")
    @PreAuthorize("@ss.hasPermission('product:spu:query')")
    public CommonResult<PageResult<ProductSpuRespVO>> getSpuPage(@Valid ProductSpuPageReqVO pageVO) {
        PageResult<ProductSpuDO> pageResult = productSpuService.getSpuPage(pageVO);
        PageResult<ProductSpuRespVO> data = BeanUtils.toBean(pageResult, ProductSpuRespVO.class);
        List<ProductSpuRespVO> list = data.getList();
        toVoList(list);
        return success(data);
    }

    private void toVoList(List<ProductSpuRespVO> list) {
        MemberConfigRespDTO config = configApiV2.getConfig(CONFIG_MEMBER, MemberConfigRespDTO.class);
        int pointDeductUnitPrice = 0;
        if (!config.isPointDeductDisable()) {
            pointDeductUnitPrice = config.getPointTradeDeductUnitPrice();
        }
        int cryptocurrencyDeductUnitPrice = config.getCryptocurrencyTradeDeductUnitPrice();
        Set<Long> shopIds = convertSet(list, ProductSpuRespVO::getShopId);
        Map<Long, ShopInfoDTO> shops = shopInfoApi.getShopInfoMap(shopIds);
        Set<Long> brandIds = list.stream().map(ProductSpuRespVO::getBrandId).collect(Collectors.toSet());
        Map<Long, ProductBrandDO> brands = productBrandService.getBrandMap(brandIds);
        for (ProductSpuRespVO vo : list) {
            toVo(vo, pointDeductUnitPrice, cryptocurrencyDeductUnitPrice);
            ShopInfoDTO shop = shops.get(vo.getShopId());
            vo.setShop(shop == null ? ShopInfoDTO.FALLBACK : shop);
            ProductBrandDO brand = brands.get(vo.getBrandId());
            vo.setBrandName(brand == null ? "不详" : brand.getName());
        }
    }

    private void toVo(ProductSpuRespVO vo, int pointDeductUnitPrice, int cryptocurrencyDeductUnitPrice) {
        for (ProductSkuRespVO sku : vo.getSkus()) {
            if (StrUtil.isBlank(sku.getPicUrl())) {
                sku.setPicUrl(vo.getPicUrl());
            }
            sku.setPointDeductUnitPrice(pointDeductUnitPrice);
            sku.setCryptocurrencyDeductUnitPrice(cryptocurrencyDeductUnitPrice);
        }
        vo.setPointDeductUnitPrice(pointDeductUnitPrice);
        vo.setCryptocurrencyDeductUnitPrice(cryptocurrencyDeductUnitPrice);
    }

    @GetMapping("/tab-count")
    @Operation(summary = "获得产品 SPU 分页页签统计", description = "用于产品 SPU 列表页在页签上展示数量")
    @PreAuthorize("@ss.hasPermission('product:spu:query')")
    public CommonResult<Map<String, Long>> getSpuCount(@RequestParam(value = "type", defaultValue = "", required = false) String type) {
        if (isSuperAdmin()) {
            return success(productSpuService.getSpuCount(null, type));
        }
        return success(productSpuService.getSpuCount(getLoginUserLastShopId(), type));
    }

    @GetMapping("/export-excel")
    @Operation(summary = "导出产品")
    @PreAuthorize("@ss.hasPermission('product:spu:export')")
    @ApiAccessLog(operateType = EXPORT)
    public void exportSpuList(@Validated ProductSpuPageReqVO reqVO,
                              HttpServletResponse response) throws IOException {
        reqVO.setPageSize(PAGE_SIZE_NONE);
        List<ProductSpuRespVO> list = getSpuPage(reqVO).getData().getList();
        // 导出 Excel
        ExcelUtils.write(response, "产品列表.xls", "数据", ProductSpuRespVO.class, list);
    }

}
